<template>
  <div>
    <Card title="用例查询" :bordered="false" :dis-hover="true">
      <div slot="extra">
        <Button
          size="small"
          type="primary"
          icon="ios-search"
          class="card-extra-item"
          @click="search"
          >查询</Button
        >
        <Button
          size="small"
          type="default"
          icon="ios-refresh"
          class="card-extra-item"
          @click="reset"
          >重置</Button
        >
        <Button
          class="card-extra-item"
          size="small"
          type="text"
          :icon="showMore ? 'ios-arrow-up' : 'ios-arrow-down'"
          @click="showMore = !showMore"
          >{{ showMore ? "收起" : "展开" }}</Button
        >
      </div>
      <Form
        inline
        label-position="right"
        :label-width="100"
        :model="searchParams"
      >
        <Row>
          <Col span="6">
            <FormItem label="所属项目" prop="project">
              <Select
                v-model="searchParams.project"
                filterable
                clearable
                @on-select="changeProjectOption"
                @on-clear="clearProject"
              >
                <Option
                  v-for="item in projects"
                  :value="item.id"
                  :key="item.id"
                  :label="item.name"
                />
              </Select>
            </FormItem>
          </Col>
          <Col span="6">
            <FormItem label="所属场景" prop="testsuite">
              <Select v-model="searchParams.testsuite" filterable clearable>
                <Option
                  v-for="item in testsuites"
                  :value="item.id"
                  :key="item.id"
                  :label="item.name"
                />
              </Select>
            </FormItem>
          </Col>
          <Col span="6">
            <FormItem label="请求接口">
              <Select
                v-model="searchParams.api"
                :max-tag-count="1"
                clearable
                multiple
                filterable
                size="default"
              >
                <Option
                  v-for="item in apis"
                  :key="item.id"
                  :value="item.id"
                  :label="item.name"
                />
              </Select>
            </FormItem>
          </Col>
          <Col span="6">
            <FormItem label="用例创建人">
              <Select
                v-model="searchParams.creator"
                filterable
                multiple
                :max-tag-count="2"
              >
                <Option
                  v-for="(item, index) in users"
                  :value="item.id"
                  :label="item.real_name"
                  :key="index"
                ></Option>
              </Select>
            </FormItem>
          </Col>
        </Row>
        <CollapseTransition>
          <div v-show="showMore">
            <Row>
              <Col span="6">
                <FormItem label="用例名称">
                  <Input
                    clearable
                    placeholder="请输入用例名称"
                    v-model="searchParams.name"
                  />
                </FormItem>
              </Col>
              <Col span="6">
                <FormItem label="用例状态">
                  <Select v-model="searchParams.status" clearable>
                    <Option value="INITIAL">初始状态</Option>
                    <Option value="PASS">通过</Option>
                    <Option value="FAIL">失败</Option>
                  </Select>
                </FormItem>
              </Col>
              <Col span="6">
                <FormItem label="重要级别">
                  <Select v-model="searchParams.level" multiple>
                    <Option
                      v-for="(item, index) in levels"
                      :value="item.value"
                      :label="item.label"
                      :key="index"
                    ></Option>
                  </Select>
                </FormItem>
              </Col>
            </Row>
          </div>
        </CollapseTransition>
      </Form>
    </Card>
    <Card title="用例列表" :bordered="false" :dis-hover="true">
      <div slot="extra">
        <span class="card-extra-item">
          <Icon
            size="24"
            :color="statusColor['INITIAL']"
            type="ios-leaf"
          />初始状态
        </span>
        <span class="card-extra-item">
          <Icon size="24" :color="statusColor['PASS']" type="ios-leaf" />通过
        </span>
        <span class="card-extra-item">
          <Icon size="24" :color="statusColor['FAIL']" type="ios-leaf" />失败
        </span>
        <Button
          class="card-extra-item"
          size="small"
          type="primary"
          @click="createTestcase = true"
          >创建用例</Button
        >
        <!-- <Button
          class="card-extra-item"
          size="small"
          type="primary"
          @click="importTestcase = true"
          >导入用例</Button
        > -->
        <Button
          class="card-extra-item"
          size="small"
          type="primary"
          @click="handleBatchExecTestcase"
          >批量执行</Button
        >
        <Button
          type="primary"
          size="small"
          class="card-extra-item"
          @click="showCreatePeriodicTaskModal"
          >创建定时任务</Button
        >
        <Button
          class="card-extra-item"
          size="small"
          type="error"
          @click="showBatchDeleteTestcaseModal"
          >删除</Button
        >
      </div>
      <Table
        :columns="testcaseColumns"
        :data="testcaseData"
        border
        size="small"
        :tooltip-max-width="500"
        @on-selection-change="changeTableSelection"
      >
        <template slot-scope="{ row }" slot="project|api">
          <tooltip placement="bottom" transfer :max-width="500">
            <div slot="content" style="white-space: normal">
              项目：{{ row.api.project.name }}
              <br />
              接口：{{ row.api.name }}
              <br />
              URL：{{ row.api.url }}
            </div>
            {{ row.api.project.name }}
            <br />
            {{ row.api.name }}
          </tooltip>
        </template>
        <template slot-scope="{ row }" slot="url">
          <Tooltip placement="bottom" transfer :max-width="500">
            <div slot="content" style="white-space: normal">
              {{
                row.url + (row.request_params ? "?" + row.request_params : "")
              }}
            </div>
            {{ row.url + (row.request_params ? "?" + row.request_params : "") }}
          </Tooltip>
        </template>
        <template slot-scope="{ row }" slot="modifier">{{
          row.modifier.real_name
        }}</template>
        <template slot-scope="{ row }" slot="level">
          <Select
            transfer
            v-model="row.level"
            @on-change="changeTestcaseLevel(row)"
          >
            <div
              slot="prefix"
              size="small"
              :class="
                'levelSelect-prefix levelOption-' + row.level.toLowerCase()
              "
            ></div>
            <Option
              v-for="(item, index) in levels"
              :value="item.value"
              :label="item.label"
              :key="index"
              :class="'levelOption levelOption-' + item.value.toLowerCase()"
            ></Option>
          </Select>
        </template>
        <template slot-scope="{ row }" slot="status">
          <Icon size="24" :color="statusColor[row.status]" type="ios-leaf" />
        </template>
        <template slot-scope="{ row }" slot="action">
          <Button
            size="small"
            type="text"
            style="color: #2d8cf0"
            @click="showCreateTestcaseModal(row)"
            >复制</Button
          >
          <Button
            size="small"
            type="text"
            style="color: #2d8cf0"
            @click="showEditDebugTestcaseModal(row)"
            >编辑<Divider type="vertical" />调试</Button
          >
        </template>
      </Table>
      <Page
        transfer
        :total="page.total"
        :current="page.current"
        :page-size="page.pageSize"
        :page-size-opts="page.pageSizeOpts"
        size="small"
        show-elevator
        show-sizer
        show-total
        prev-text="上一页"
        next-text="下一页"
        style="margin-top: 15px"
        @on-change="change"
        @on-page-size-change="pageSizeChange"
      />
    </Card>
    <PeriodicTaskCreate
      :createPeriodicTask.sync="createPeriodicTask"
      :task.sync="periodicTask"
      :args.sync="periodicTaskArgs"
      :showKwargs="false"
    ></PeriodicTaskCreate>
    <TestcaseCreate
      :createTestcase.sync="createTestcase"
      @initTestcaseTable="search"
      :testcase.sync="originTestcase"
    ></TestcaseCreate>
    <TestcaseEditDebug
      :editDebugTestcase.sync="editDebugTestcase"
      :testcase.sync="testcase"
      @initTestcaseTable="search"
    ></TestcaseEditDebug>
    <TestcaseImport
      :importTestcase.sync="importTestcase"
      @initTestcaseTable="search"
    ></TestcaseImport>
    <Modal
      v-model="deleteTestcaseConfirm"
      title="删除用例"
      width="550"
      :mask-closable="false"
      @on-cancel="handleDeleteTestcaseConfirmCancel"
    >
      部分用例已与场景相关联，请选择删除方式
      <div slot="footer">
        <Button type="warning" @click="handleDeleteTestcaseConfirmSubmit(false)"
          >只删除未关联场景的用例</Button
        >
        <Button type="error" @click="handleDeleteTestcaseConfirmSubmit(true)"
          >删除用例并解绑关联场景</Button
        >
        <Button type="primary" @click="handleDeleteTestcaseConfirmCancel"
          >取消</Button
        >
      </div>
    </Modal>
  </div>
</template>

<script>
import PeriodicTaskCreate from "@/view/components/CeleryScheduledTaskService/periodic-task/periodic-task-create";
import TestcaseCreate from "./testcase-create";
import TestcaseEditDebug from "./testcase-edit-debug";
import TestcaseImport from "./testcase-import";
import CollapseTransition from "_c/collapse-transition/collapse-transition.js";
import {
  getTestcases,
  batchDeleteTestcase,
  batchExecTestcase,
  partialUpdateTestcase,
} from "@/api/HttpAutoTestService/testcase";
import { getProjectNames } from "@/api/HttpAutoTestService/project";
import { getTestsuiteNames } from "@/api/HttpAutoTestService/testsuite";
import { getApiNames } from "@/api/HttpAutoTestService/api";
import { getUserNames } from "@/api/HttpAutoTestService/user";
import SelectTree from "_c/select-tree";

export default {
  name: "testcase",
  components: {
    PeriodicTaskCreate,
    TestcaseCreate,
    TestcaseEditDebug,
    TestcaseImport,
    CollapseTransition,
    SelectTree,
  },
  watch: {
    $route() {
      // 监听路由参数 所属项目、请求接口
      let project = this.$route.query.project;
      if (project !== undefined) {
        this.searchParams.project = project;
      }
      let api = this.$route.query.api;
      this.searchParams.api = [];
      if (api !== undefined) {
        this.searchParams.api = [api];
      }
      this.search();
    },
  },
  mounted() {
    let project = this.$route.query.project;
    if (project !== undefined) {
      this.searchParams.project = project;
    }
    let api = this.$route.query.api;
    this.searchParams.api = [];
    if (api !== undefined) {
      this.searchParams.api = [api];
    }
    this.searchParams.creator = [this.$store.state.user.id];
    // 获取用例列表数据
    this.search();
    // 获取项目
    this.getProjectNames();
    // 获取场景
    this.getTestsuiteNames();
    // 获取接口
    this.getApiNames();
    // 获取用户
    getUserNames()
      .then((res) => {
        this.users = res.data;
      })
      .catch((err) => {
        this.$Modal.error({
          title: "系统异常，请联系管理员……",
          content: JSON.stringify(err),
          closable: true,
        });
      });
  },
  data() {
    return {
      showMore: false,
      createPeriodicTask: false,
      createTestcase: false,
      editDebugTestcase: false,
      deleteTestcaseConfirm: false,
      importTestcase: false,
      statusColor: {
        INITIAL: "#2db7f5",
        PASS: "#19be6b",
        FAIL: "#ed4014",
      },
      searchParams: {
        name: "",
        project: "",
        testsuite: "",
        api: [],
        status: "",
        level: [],
        creator: [],
      },
      testcaseColumns: [
        {
          type: "selection",
          width: 60,
          align: "center",
          fixed: "left",
        },
        {
          title: "用例名称",
          key: "name",
          width: 350,
          tooltip: true,
        },
        {
          title: "项目|接口",
          slot: "project|api",
          width: 350,
          ellipsis: true,
        },
        {
          title: "请求URL",
          slot: "url",
          width: 350,
          ellipsis: true,
        },
        {
          title: "Headers参数",
          key: "headers",
          width: 350,
          ellipsis: true,
        },
        {
          title: "Body参数类型",
          key: "request_data_type",
          width: 120,
          align: "center",
        },
        {
          title: "Body参数",
          key: "request_data",
          width: 350,
          ellipsis: true,
        },
        {
          title: "期望结果",
          key: "expect_result",
          width: 350,
          ellipsis: true,
        },
        {
          title: "最近维护人",
          slot: "modifier",
          align: "center",
          width: 120,
        },
        {
          title: "重要级别",
          slot: "level",
          align: "center",
          width: 120,
        },
        {
          title: "状态",
          slot: "status",
          align: "center",
          width: 65,
          fixed: "right",
        },
        {
          title: "操作",
          slot: "action",
          width: 170,
          align: "center",
          fixed: "right",
        },
      ],
      testcaseData: [],
      selectedTestcases: [],
      periodicTask: "",
      periodicTaskArgs: "[]",
      projects: [],
      testsuites: [],
      apis: [],
      levels: [
        { value: "LOW", label: "低" },
        { value: "NORMAL", label: "中" },
        { value: "HIGH", label: "高" },
        { value: "HIGHER", label: "更高" },
      ],
      users: [],
      testcase: {
        id: "",
        name: "",
        api: "",
        url: "",
        headers: {},
        request_data_type: "",
        request_params: "",
        request_data: {},
        expect_result: {},
        remark: "",
      },
      originTestcase: {
        api: "",
        url: "",
        headers: {},
        request_data_type: "",
        request_params: "",
        request_data: {},
        expect_result: {},
        remark: "",
      },
      page: {
        current: 1,
        total: 0,
        pageSize: 50,
        pageSizeOpts: [10, 30, 50, 100, 200],
      },
    };
  },
  methods: {
    reset() {
      this.searchParams = {
        name: "",
        project: "",
        testsuite: "",
        api: [],
        status: "",
        level: [],
        creator: [],
      };
      this.getTestsuiteNames();
      this.getApiNames();
      this.search();
    },
    search(page) {
      let data = {
        name: this.searchParams.name,
        project: this.searchParams.project,
        testsuite: this.searchParams.testsuite,
        api: this.searchParams.api.toString(),
        status: this.searchParams.status,
        level: this.searchParams.level.toString(),
        creator: this.searchParams.creator.toString(),
        page: 1,
        page_size: this.page.pageSize,
      };
      if (typeof page == "number") {
        data.page = page;
      }
      this.page.current = data.page;

      getTestcases(data)
        .then((res) => {
          const data = res.data;
          this.testcaseData = data.results;
          this.page.total = data.count;
          if (data.next === null) {
            this.page.current = Math.ceil(this.page.total / this.page.pageSize);
          }
          if (data.previous === null) {
            this.page.current = 1;
          }
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    showBatchDeleteTestcaseModal() {
      if (this.selectedTestcases.length > 0) {
        this.deleteTestcaseConfirm = true;
      } else {
        this.$Message.info("请选择需要删除的用例");
      }
    },
    handleDeleteTestcaseConfirmCancel() {
      this.deleteTestcaseConfirm = false;
      this.search();
      this.selectedTestcases = [];
    },
    handleDeleteTestcaseConfirmSubmit(unbundle) {
      let data = {
        unbundle: unbundle,
        testcases: this.selectedTestcases,
      };
      batchDeleteTestcase(data)
        .then((res) => {
          this.$Message.info("删除成功");
          this.handleDeleteTestcaseConfirmCancel();
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    change(val) {
      this.page.current = val;
      this.search(val);
    },
    pageSizeChange(val) {
      this.page.pageSize = val;
      this.search();
    },
    showCreateTestcaseModal(row) {
      let data = {
        url: row.url,
        headers: row.headers,
        request_data_type: row.request_data_type,
        request_params: "",
        request_data: row.request_data,
        expect_result: row.expect_result,
        remark: row.remark,
        project: row.api.project.id,
        api: row.api.id,
      };
      let request_params = row.request_params;
      if (request_params) {
        data.url = data.url + "?" + request_params;
      }
      this.originTestcase = data;
      this.originTestcase.api = row.api.id;
      this.createTestcase = true;
    },
    showEditDebugTestcaseModal(row) {
      let data = {
        id: row.id,
        name: row.name,
        project: row.api.project.id,
        api: row.api.id,
        url: row.url,
        headers: row.headers,
        request_data_type: row.request_data_type,
        request_params: "",
        request_data: row.request_data,
        expect_result: row.expect_result,
        remark: row.remark,
      };
      let request_params = row.request_params;
      if (request_params) {
        data.url = data.url + "?" + request_params;
      }
      this.testcase = data;
      this.editDebugTestcase = true;
    },
    changeTableSelection(val) {
      this.selectedTestcases = val.map((item) => {
        return item.id;
      });
    },
    // 选择项目
    changeProjectOption(val) {
      let project = val.value;
      this.searchParams.project = project;
      this.getTestsuiteNames(project);
      this.getApiNames(project);
      this.search();
    },
    // 清空选择的项目
    clearProject() {
      this.searchParams.project = "";
      this.getTestsuiteNames();
      this.getApiNames();
      this.search();
    },
    // 获取项目
    getProjectNames() {
      getProjectNames()
        .then((res) => {
          this.projects = res.data;
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    // 获取场景
    getTestsuiteNames(project) {
      getTestsuiteNames({ project: project })
        .then((res) => {
          this.testsuites = res.data;
          if (Array.isArray(this.testsuites)) {
            let testsuiteIds = this.testsuites.map((item) => {
              return item.id;
            });
            if (!testsuiteIds.includes(this.searchParams.testsuite)) {
              this.searchParams.testsuite = "";
            }
          }
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    // 获取接口
    getApiNames(project) {
      getApiNames({ project: project })
        .then((res) => {
          this.apis = res.data;
          let apiTemp = [];
          if (Array.isArray(this.apis) && this.searchParams.api.length > 0) {
            let apiIds = this.apis.map((item) => {
              return item.id;
            });
            apiTemp = this.searchParams.api.filter((item) => {
              return apiIds.includes(item);
            });
          }
          this.searchParams.api = apiTemp;
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    // 批量执行测试用例
    handleBatchExecTestcase() {
      if (this.selectedTestcases.length > 0) {
        let data = {
          testcases: this.selectedTestcases,
        };
        batchExecTestcase(data).then((res) => {
          this.$Message.info(res.data);
          this.search();
        });
        return;
      }
      this.$Message.info("请选择需要执行的用例");
    },
    showCreatePeriodicTaskModal() {
      this.periodicTask =
        "批量执行测试用例:HttpAutoTestService.testcase_task.batch_exec_testcase";
      if (this.selectedTestcases.length > 0) {
        let temp = JSON.stringify(this.selectedTestcases).replace(/\"/g, "'");
        this.periodicTaskArgs = `["${temp}"]`;
        this.createPeriodicTask = true;
        return;
      }
      this.$Message.info("请选择需要创建定时任务的用例");
    },
    changeTestcaseLevel(row) {
      const { id, level } = row;
      partialUpdateTestcase({ id, level })
        .then((res) => {
          if (res.status === 200) {
            this.$Message.info("修改成功");
          } else {
            this.$Message.error("修改失败");
          }
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
  },
};
</script>

<style scoped>
.levelSelect-prefix {
  width: 15px;
  height: 15px;
  border-radius: 50%;
}
.levelOption {
  color: #fff;
}
.levelOption-low {
  background-color: #2db7f5;
}
.levelOption-normal {
  background-color: #19be6b;
}
.levelOption-high {
  background-color: #ff9900;
}
.levelOption-higher {
  background-color: #ed4014;
}
.ivu-form-item {
  width: 100%;
}
</style>
